use log::info;
use rocket::serde::Deserialize;

#[macro_use]
extern crate rocket;

use rocket_db_pools::{Database, Connection};
use rocket_db_pools::sqlx::{self, Row};
use rocket::serde::json::Json;
use rocket::tokio::time::{sleep, Duration};

#[derive(Database)]
#[database("sqlite_logs")]
struct Logs(sqlx::SqlitePool);

#[derive(Debug, Deserialize)]
#[serde(crate = "rocket::serde")]
struct User {
    id: i64,
    name: String,
}

#[get("/<id>")]
async fn read(mut db: Connection<Logs>, id: i64) -> Option<String> {
    sqlx::query("SELECT * FROM user WHERE id = ?").bind(id)
        .fetch_one(&mut **db).await
        .and_then(|r| {
            let row = r.try_get(0);
            println!("result {:?}", row);
            Ok(row?)
        })
        .ok()
}

#[get("/list")]
async fn list(mut db: Connection<Logs>) -> Option<String> {
    let result: Option<String> = sqlx::query("SELECT * FROM user")
        .fetch_all(&mut **db)
        .await
        .map(|rows| {
            let names: Vec<String> = rows
                .into_iter()
                .map(|row| {
                    let id: i32 = row.try_get("id").unwrap_or_default();
                    let name: String = row.try_get("name").unwrap_or_default();
                    format!("id: {}, name: {}", id, name)
                })
                .collect();
            names.join(", ") // 将所有名称连接成一个字符串，可以根据需要调整
        })
        .ok();

    result // 最后一行，没有分号，因此就是返回值
}

#[post("/", data = "<data>")]
async fn insert(mut db: Connection<Logs>, data: Json<User>) -> String {
    let name = &data.name; // Assuming you want to insert the 'name' field


    if let Err(e) = sqlx::query("create table  IF NOT EXISTS `user`
        (
            id   integer not null
            constraint table_name_pk
            primary key autoincrement,
            name varchar(120)
        );")
        .execute(&mut **db)
        .await
    {
        error!("Failed to execute query: {:?}", e);
        return "Error inserting data".to_string();
    }

    if let Err(e) = sqlx::query("INSERT INTO user (name) VALUES (?)")
        .bind(name)
        .execute(&mut **db)
        .await
    {
        error!("Failed to execute query: {:?}", e);
        return "Error inserting data".to_string();
    }

    "Data inserted successfully".to_string()// 最后一行，没有分号，因此就是返回值
}

#[get("/")]
fn index() -> &'static str {
    println!("正在访问中");
    "Hello, world! from Rust Rocket Web Framework"
}

// http://127.0.0.1:8000/rust?param=34
#[get("/rust?<param>")]
fn info(param: Option<u64>) -> String {
    info!("这个是rust编写 log {:?}",param);
    format!("这个是rust编写 {:?}", param.unwrap())// 最后一行，没有分号，因此就是返回值
}

//  http://localhost:8000/hello/eric/28
#[get("/<name>/<age>")]
fn hello(name: &str, age: u8) -> String {
    format!("Hello, {} year old named {}!", age, name)// 最后一行，没有分号，因此就是返回值
}

#[get("/hello/<name>/<age>/<cool>")]
fn hello_cool(name: &str, age: u8, cool: bool) -> String {
    if cool {
        format!("You're a cool {} year old, {}!", age, name)
    } else {
        format!("{}, we need to talk about your coolness.", name)
    }
}

#[get("/delay/<seconds>")]
async fn delay(seconds: u64) -> String {
    sleep(Duration::from_secs(seconds)).await;
    format!("Waited for {} seconds", seconds) // 最后一行，没有分号，因此就是返回值
}

//  不需要main方法，可以直接 cargo run 或者在RustRover右键运行
// #[launch]
// fn rocket() -> _ {
//     info!("INFO");
//     rocket::build()
//         .attach(Logs::init())
//         .mount("/hello", routes![hello])
//         .mount("/", routes![info])
//         .mount("/", routes![index])
//         .mount("/id/", routes![read])
//         .mount("/id/", routes![insert])
//         .mount("/", routes![list])
// }


#[rocket::main]
async fn main() -> Result<(), rocket::Error> {
    let _rocket = rocket::build()
        .attach(Logs::init())
        .mount("/hello", routes![hello])
        .mount("/", routes![info])
        .mount("/", routes![index])
        .mount("/id/", routes![read,insert])
        .mount("/", routes![list])
        .mount("/", routes![delay])
        .launch()
        .await?;
    Ok(())
}